namespace FIREFLYX {
    /** 标准 PBR 着色器*/
    export const BUILTIN_SHADER_STANDARD = `standard`;
    DefaultAsset.shaderGenMap[BUILTIN_SHADER_STANDARD] = () => {
        const vsCode = `#version 300 es
        precision mediump float;
        //顶点、UV、法线、切线
        layout (location = 0) in vec4 a_Position; //顶点 位置 是有默认值的 (0,0,0,1)
        layout (location = 3) in vec2 a_UV;       //UV 纹理坐标
        layout (location = 1) in vec3 a_Normal;   //法线 向量
        layout (location = 2) in vec4 a_Tangent;  //切线 向量
        uniform ubo_model_block{
            mat4 u_mMtx;                //模型矩阵
        } uboModel;
        uniform ubo_cam_block{
            mat4 u_viewMtx;             //视窗矩阵
            mat4 u_projectMtx;          //投影矩阵
            vec4 u_eyePos;              //眼睛位置
        } uboCam;
        
        out vec3 v_wPos;
        out vec2 v_uv;
        out vec3 v_wNormal;
        out mat3 v_TBN_Mtx;

        //构建 世界空间下 的 TBN 空间矩阵
        //it_m_mtx 转到世界间 逆转置 矩阵 (魔法矩阵)
        //_normal 顶点法线向量
        //_tangent 顶点切线向量
        mat3 MakeTBNMatrix(mat3 it_m_mtx,lowp vec3 _normal,lowp vec4 _tangent)
        {
            vec3 normal = normalize(it_m_mtx * _normal);
            vec3 tangent = normalize(it_m_mtx * _tangent.xyz);
            vec3 binormal = cross(normal , tangent) * _tangent.w;
            return mat3(tangent , binormal , normal);
        }

        void main() {
            v_uv = a_UV;
            mat3 it_mMtx = mat3(transpose(inverse(uboModel.u_mMtx)));
            v_wNormal = it_mMtx * a_Normal;         //逆转置矩阵,可以让法向量在非统一缩放后保持准确,不受干扰。
            vec4 mPos = vec4(a_Position.xyz,1.0);
            v_wPos = (uboModel.u_mMtx * mPos).xyz;
            //TBN 空间矩阵
            v_TBN_Mtx = MakeTBNMatrix(it_mMtx , a_Normal , a_Tangent);
            // mat4 mvpMat = u_projectMtx * u_viewMtx * uboModel.u_mMtx;
            mat4 mvpMat = uboCam.u_projectMtx * uboCam.u_viewMtx * uboModel.u_mMtx;
            gl_Position = mvpMat * a_Position;
        }
        `;

        const fsCode = `#version 300 es
        precision mediump float;
        uniform sampler2D u_mainTex;        
        uniform vec4 u_mainColor;           //主颜色 颜色
        uniform sampler2D u_metaRougTex;    //金属粗糙度纹理
        uniform sampler2D u_normalTex;      //法线纹理
        uniform samplerCube u_skybox;       //环境漫反射 纹理

        uniform ubo_cam_block{
            mat4 u_viewMtx;                     //视窗矩阵
            mat4 u_projectMtx;                  //投影矩阵
            vec4 u_eyePos;                      //眼睛位置
        } uboCam;

        uniform ubo_light_block{
            uniform vec4 _mainLightDir;
            uniform vec4 _mainLightColor;
            uniform vec4[64] _addLightsPos;
            uniform vec4[64] _addLightsColor;
            uniform vec4[64] _addLightsAtt;
            uniform vec4[64] _addLightsSpotDir;
        } uboLight;

        in vec3 v_wPos;
        in vec2 v_uv;
        in vec3 v_wNormal;
        in mat3 v_TBN_Mtx;

        out vec4 color;

        #define PI 3.1415926
        #define Nonmetal_F0 vec3(0.04,0.04,0.04)

        vec3 UnpackNormal(vec4 nTexRGB){
            return nTexRGB.rgb * 2. - 1.;
        }

        float saturate(float x){
            return clamp(x, 0.0, 1.0);
        }

        float chiGGX(float v)
        {
            return v > 0. ? 1. : 0.;
        }

        float GGX_PartialGeometryTerm(float alpha , float _oN , float _oH){
            float VoH2 = saturate(_oN);
            float chi = chiGGX( VoH2 / saturate(_oH) );
            VoH2 = VoH2 * VoH2;
            float tan2 = ( 1. - VoH2 ) / VoH2;
            return (chi * 2.) / ( 1. + sqrt( 1. + alpha * alpha * tan2 ) );
        }

        float G_GGX(float _Roughness , float NoV , float NoL , float VoH, float LoH){
            float g = GGX_PartialGeometryTerm(_Roughness,NoV,VoH) * GGX_PartialGeometryTerm(_Roughness,NoL,LoH);
            return max(0.0001 , g);
        }

        // Fresnel [1994] Schlick
        vec3 Fresnel_Schlick(float cosT, vec3 F0)
        {
            return F0 + (1. - F0) * pow(1. - cosT, 5.);
        }

        // GGX [2007] Trowbridge-Reitz
        float UE_D_GGX(float Roughness , float NoH){
            float a = Roughness * Roughness;
            float a2 = a * a;
            float d = (NoH * a2 - NoH) * NoH + 1.0;
            // return a2 / max(HALF_EPS , PI * d * d);
            return (a2 / (PI * d * d));
        }

        //indirect diff Fresnel Schlick , c to I_Kd
        vec3 I_D_Fresnel_Schlick(float cosT, vec3 F0 , float roughness)
        {
            float _r = 1. - roughness;
            vec3 _A = max(vec3(_r,_r,_r) , F0);
            return F0 + (_A - F0) * pow(1. - cosT, 5.);
        }

        //直接光 镜面反射
        vec3 Direct_BRDF_Specular(float _Roug , float _Met , float NoV , float NoL , float NoH , float VoH , float LoH , vec3 F0, out vec3 D_ks){
            //直接光 spec , BRDF f(l,v) = D*F*G / 配平值

            //      D (h), GGX[2007]
            // half a2 = Pow4(_Roug);
            float D = UE_D_GGX(_Roug , NoH);

            //      F (v,h), Schlick[1994]
            // vec3 F = Fresnel_Schlick(saturate(VoH),_F0.xyz);
            vec3 F = Fresnel_Schlick(saturate(VoH), F0);
            // vec3 F = UE_F_Fresnel(_F0,VoH);

            //      G (l,v,h), Schlick-GGX
            // float G = UE_G_Vis_Schlick(_Roug , saturate(NoV) , saturate(NoL));
            // float G = UE_Vis_smithJointApprox(_Roug , NoV , NoL);
            float G = G_GGX(_Roug , NoV , NoL , VoH , LoH);

            //      配平值 4*(n.l)(n.v)
            float S_denominator = 4. * NoL * NoV;


            D_ks = F;
            // return D * G * F / S_denominator;
            return D * G * F ;
        }

        //间接光
        vec3 Indirect_BRDF(float _Roug , float _Met, vec3 ALBEDO, vec3 N ,vec3 R , float NoV,vec3 F0){
            //间接光 diff ,cubeMap 模糊(mip)
            // vec3 I_Diff = SAMPLE_TEXTURECUBE_LOD(_EvnMap, sampler_EvnMap, R, 10).rgb;
            vec3 I_F = I_D_Fresnel_Schlick(saturate(NoV), F0 ,_Roug);
            // vec3 I_F = I_D_Fresnel_Schlick(saturate(NoV), vec3(0.04,0.04,0.04) ,_Roug);
            vec3 I_kd = (1. - I_F) * (1. - _Met);
            // vec3 irradiance = SAMPLE_TEXTURECUBE_LOD(_EvnMap, sampler_EvnMap, N, mip).rgb;
            vec3 irradiance = textureLod(u_skybox, N, 7.).rgb;
            // vec3 I_Diff = irradiance/PI * ALBEDO;  //
            vec3 I_Diff = irradiance * ALBEDO;

            // //间接光 spec ,IBL
            // // vec3 I_ks = 0;
            // // vec3 I_kd = (1 - I_ks) * (1 - _Met);
            // vec3 I_S_BRDF_I = SAMPLE_TEXTURE2D(_BRDFLUT, sampler_BRDFLUT, vec2(saturate(NoV),_Roug)).rgb;
            // vec3 reflection = prefilteredReflection(R, _Roug).rgb;	
            // vec3 I_Specular =  reflection * (I_F * I_S_BRDF_I.x + I_S_BRDF_I.y);
            
            // vec3 I_Color = I_Diff * I_kd + I_Specular;
            vec3 I_Color = I_Diff ;
            return I_Color;
        }

        void main(){
            vec4 texColor = texture(u_mainTex , v_uv) * u_mainColor;                    //纹理颜色
            vec4 texMetRoug = texture(u_metaRougTex , v_uv);                            //金属度+粗糙度 纹理
            vec3 ALBEDO = texColor.rgb;
            vec4 texNormal = texture(u_normalTex , v_uv);                               //法线纹理


            vec3 L = uboLight._mainLightDir.xyz * -1.0;                                             //L  指向光源的方向
            // vec3 N = normalize(v_wNormal);                                                       //N  世界法向量(normalize 是必须的,因为片元上的wNormal是差值得到,长度不一定等于1了)
            vec3 N = normalize(v_TBN_Mtx * UnpackNormal(texNormal));                                //N  世界法向量
            vec3 V = normalize(uboCam.u_eyePos.xyz - v_wPos.xyz);                                   //V  指向相机
            vec3 H = normalize(V + L);
            vec3 R = reflect(-V,N);                                                              //H  半角向量
            float NoL = dot(N,L);
            float NoV = dot(N,V);
            // float NoH = (dot(N,H));
            // float VoH = (dot(V,H));
            // float LoH = (dot(L,H));
            float NoH = saturate(dot(N,H));
            float VoH = saturate(dot(V,H));
            float LoH = saturate(dot(L,H));

            
            float _Met = 0.5 * texMetRoug.r;
            float _Roug = 0.9 * texMetRoug.g;
            vec3 F0 = mix(Nonmetal_F0 , ALBEDO , _Met);
            vec3 D_ks = vec3(0.);

            //--------------------直接光照----------------------------
            //  Blinn-Phong 镜面反射
            float spec = pow(max(0.0, dot(H , N)) , max(0.01 , 100.)) * step(0.0 , NoL);            //Blinn-Phong 的 spec (镜面反射) 乘 step(0.0 , NoL) 保证受光面半球才有高光 
            vec3 dirSpecColor = uboLight._mainLightColor.rgb * spec ;
            //  GGX 镜面反射
            dirSpecColor = Direct_BRDF_Specular(_Roug , _Met , NoV , NoL , NoH , VoH , LoH , F0, D_ks);

            //  漫反射
            float diffuse = NoL;                                                                                              //diffuse (漫反射)
            vec3 dirDiffColor = uboLight._mainLightColor.rgb * texColor.xyz * diffuse ;
            vec3 D_kd = (1. - D_ks) * (1. - _Met);
            dirDiffColor *= D_kd;

            vec3 dirLightContribute = dirDiffColor + dirSpecColor;
            //--------------------------------------------------------

            //--------------------间接光照----------------------------

            // vec3 indirectContribute = vec3(0,0,0);
            vec3 indirectContribute = Indirect_BRDF(_Roug , _Met , ALBEDO,  N , R ,  NoV, F0);
            //--------------------------------------------------------
            
            // vec3 dirLightContribute = dirDiffColor;
            // vec3 dirLightContribute = dirSpecColor;

            // color = vec4(shadow,0.0,0.0,1.0);
            //color = vec4(1.0,0.0,0.0,1.0);
            //color = vec4(v_uv.x,v_uv.y,0.0,1.0);
            //color = texColor;
            //color = vec4(v_wPos , 1.0);
            //color = vec4(uboLight._mainLightColor , 1.0);
            //color = vec4(uboCam.u_eyePos.xyz , 1.0);
            //color = vec4(L , 1.0);
            // color = vec4(N , 1.0);

            // color = vec4(H * NoL, 1.0);
            // color = vec4(V, 1.0);

            //color = vec4(diffuse,diffuse,diffuse , 1.0);
            //color = vec4(spec,spec,spec , 1.0);
            //color = vec4(dirDiffColor , 1.0);
            //color = vec4(dirSpecColor , 1.0);
            // color = vec4(texNormal.rgb , 1.0);

            color = vec4(dirLightContribute + indirectContribute, max (texColor.a , spec));
         }
        `;
        //glsl
        const vs = new GLSL();
        vs.setCode(vsCode);
        const fs = new GLSL();
        fs.setCode(fsCode);

        //shader
        let result: Shader = new Shader();
        result.tag = BUILTIN_SHADER_STANDARD;
        result.lightMode = RenderPipeline.LM_FORWARD;
        result.vertexGLSL = vs;
        result.fragmentGLSL = fs;
        //unifrom 默认值
        result.definePropertyMap = {};
        //
        result.definePropertyMap.u_mainTex = {
            type: "texture",
            value: "white"
        };
        //
        result.definePropertyMap.u_metaRougTex = {
            type: "texture",
            value: "white"
        };
        //法线纹理
        result.definePropertyMap.u_normalTex = {
            type: "texture",
            value: "normal"
        };
        //
        result.definePropertyMap.u_mainColor = {
            type: "color",
            value: [1, 1, 1, 1]
        };

        //apply
        result.apply();

        return result;
    };
}